#include <iostream>
#include <string>
#include "test.h"
#include "testTypeSupport.h"
#include "dcps/domain/domainparticipantfactory.h"
#include "dcps/domain/domainparticipant.h"
#include "dcps/topic/topic.h"
#include "dcps/subscribe/subscriber.h"
#include "dcps/subscribe/datareader.h"

USING_AGIDDS_NAMESPACE

int main(int argc, char* argv[]) {
    // Create DomainParticipantFactory
    DomainParticipantFactory* factory = DomainParticipantFactory::get_instance();
    if (!factory) {
        std::cerr << "Failed to get DomainParticipantFactory instance" << std::endl;
        return -1;
    }
    // Create DomainParticipant
    DomainParticipant* participant = factory->create_participant(0, PARTICIPANT_QOS_DEFAULT, nullptr, STATUS_MASK_NONE);
    if (!participant) {
        std::cerr << "Failed to create DomainParticipant" << std::endl;
        return -1;
    }
    // Create Subscriber
    Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT, nullptr, STATUS_MASK_NONE);
    if (!subscriber) {
        std::cerr << "Failed to create Subscriber" << std::endl;
        return -1;
    }
    // Register Type
    TypeSupport* testTypeSupport = test::ComplexStructTypeSupport::get_instance();
    if (!testTypeSupport) {
        std::cerr << "Failed to get TypeSupport instance" << std::endl;
        return -1;
    }
    ReturnCode_t retcode = participant->registe_type("test_ComplexStructTypeSupport", testTypeSupport);
    if (retcode != RETCODE_OK) {
        std::cerr << "Failed to register type" << std::endl;
        return -1;
    }
    // Create Topic
    Topic* topic = participant->create_topic("test_ComplexStruct", "test_ComplexStructTypeSupport", TOPIC_QOS_DEFAULT, nullptr, STATUS_MASK_NONE);
    if (!topic) {
        std::cerr << "Failed to create Topic" << std::endl;
        return -1;
    }
    // Create DataReader
    DataReader* reader = subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT, nullptr, STATUS_MASK_NONE);
    if (!reader) {
        std::cerr << "Failed to create DataReader" << std::endl;
        return -1;
    }
    // Receive data
    test::ComplexStruct data;
    SampleInfo info;
    while (true) {
        ReturnCode_t status = reader->take_next_sample(&data, info);
        if (status == RETCODE_OK && info.valid_data) {
            // Check received data
            bool isValid = true;
            isValid &= (data.name == "Example Name");
            isValid &= (data.structMem.enumVal == test::RED);
            isValid &= (data.structMem.bVal == true);
            isValid &= (data.structMem.cVal == 'A');
            isValid &= (data.structMem.oVal == 255);
            isValid &= (data.structMem.int8Val == -128);
            isValid &= (data.structMem.uint8Val == 255);
            isValid &= (data.structMem.wcVal == L'B');
            isValid &= (data.structMem.shortVal == -32768);
            isValid &= (data.structMem.ushortVal == 65535);
            isValid &= (data.structMem.int16Val == 12345);
            isValid &= (data.structMem.uint16Val == 54321);
            isValid &= (data.structMem.longVal == -2147483648);
            isValid &= (data.structMem.ulongVal == 4294967295);
            isValid &= (data.structMem.int32Val == 123456789);
            isValid &= (data.structMem.uint32Val == 987654321);
            isValid &= (data.structMem.floatVal == 3.14f);
            isValid &= (data.structMem.doubleVal == 2.71828);
            isValid &= (data.structMem.ldoubleVal.ld == 1.61803398875);
            isValid &= (data.structMem.llVal == -9223372036854775807LL);
            isValid &= (data.structMem.ullVal == 18446744073709551615ULL);
            isValid &= (data.structMem.int64Val == 1234567890123456789LL);
            isValid &= (data.structMem.uint64Val == 987654321098);

            if (isValid) {
                std::cout << "Received data matches expected values." << std::endl;
            } else {
                std::cerr << "Received data does not match expected values!" << std::endl;
            }
        } else if (status != RETCODE_NO_DATA) {
            std::cerr << "Failed to take data: " << status << std::endl;
        }
    }
    return 0;
}
